#ifndef PBVP_CONTOUR_NODE_H
#define PBVP_CONTOUR_NODE_H

#include <assert.h>

#include <map>
#include <vector>
#include <QList>

#include "arc.h"

namespace PBVP {
	/// SuperNode -- A class representing nodes in a contour tree
	class SuperNode {
	public:
		/// <summary>
		/// Construct a node with id i. 
		/// </summary>
		/// <param name="i"></param>
		/// <param name="val></param>
		SuperNode(int i = -1, float _val = 0.f);

		///
		~SuperNode() {}

		/**
		 * Copy Constructor 
		 * @note The neighbor info is not copied 
		 * @param node
		 */
		SuperNode(const SuperNode& node);

		/**
		 * Assignment Operator 
		 * @note The neighbor info is not copied 
		 * @param node
		 * 
		 * @return SuperNode&
		 */
		SuperNode& operator = (const SuperNode& node);

		/// <summary>
		/// Get the number of neighboring nodes. 
		/// </summary>
		/// <returns>int</returns>
		int degree() const { 
			return(int)(neighbors.size()); 
		}

		/// <summary>
		/// Add a neighbor of id n.
		/// </summary>
		/// The tag is used for finding starting cell for contour extraction
		/// <param name="nid"> The id of neighbor node </param>
		/// <param name="x"> The tag of neighbor node </param>
		void addNeighbor(int nid, int x = -1);


		/// <summary>
		/// Remove the neighbor with id n 
		/// </summary>
		/// <param name="nid"> The id of the node to be removed </param>
		void removeNeighbor(int nid);

		/** 
		 * Get Id of the nth neighbor.
         * @note n must be < node's degree 
		 * 
		 * @param n
		 * 
		 * @return int Id of the nth neighbor
		 */
		int getNeighborAt(int n);

		/// Get the tag of nth neighbor
		int getTagAt(int n);

		/// Get the tag of the neighbor with Id as nid
		int getNeighborTag(int nid);

		/**
		* Get the ID of a super-node.
		*/
		int getID() const { 
			return id;
		}

		/** 
		 * Add an arc to a neighboring node.
		 * 
		 * @param nid The Id of the neighbor
		 * @param pArc
		 */
		void addArc(int nid, const SuperArc& arc) {
			arcs[nid] = arc;
		}

		/**
		* Return the pointer to the SuperArc between this node and node n
		*/
		SuperArc& getArc(int nid) {
			return arcs[nid];
		}

		///
		void removeArc(int nid) {
			arcs.erase(nid);
		}

		/// <summary>
		/// less than < operator
		/// </summary>
		/// <param name="sn"></param>
		/// <returns>bool</returns>
		inline bool operator < (const SuperNode& sn) const;

		/// 
		bool operator == (const SuperNode& sn) const
		{
			return (id == sn.id);
		}

		/// 
		bool operator != (const SuperNode& sn) const
		{
			return (id != sn.id);
		}
		
		/// The unique id of the critical point
		int id;
		/// The value of the critical point
		float val;

		/**
		* The following variable are used for computing the topology of contours.
		*/
		/// Euler number of val-e
		int LS;		
		/// Euler number of val+e
		int US;			
		/// Difference between the boundary edges of L(val-e) and L(val+e)
		int dbe;

	private:
		/// SuperNode Neighbor
		/** 
		 * nei: neighbor Id
		 * tag; neighbor tag (used for contour extraction)
		 */
		struct SNodeNeighbor {
			SNodeNeighbor(int n, int x) : nei(n), tag(x) {}

			int nei;
			int tag;
		};

		std::vector<SNodeNeighbor> neighbors;
		std::map<int, SuperArc> arcs;  
	};

	bool SuperNode::operator < (const SuperNode& sn) const
	{
		if(val < sn.val) return true;
		else if(val > sn.val) return false;
		else if(id < sn.id) return true;
		return false;
	}

	bool SNLess (const SuperNode& sn1, const SuperNode& sn2); 

	typedef SuperNode CriticalPoint;
}
#endif


